package de.hsma.srn.model.user;

import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;

import com.thoughtworks.xstream.XStream;

import de.hsma.srn.model.key.KeyBoxModel;

public class UserListModel extends java.util.Observable implements Iterable<UserModel> {
	/*
	 * Members
	 */
	private HashSet<UserModel> mList;

	/*
	 * Constructors
	 */
	/**
	 * Creates a new UserList or recreate an userList if already existing.
	 * Therefore the whole Users directory is scanned for sub directories, if
	 * such a sub directory contains a .profile file the user will be recreated.
	 * Also an existing .keybox will causes an existing KeyBox!
	 */
	public UserListModel() {
		this.mList = new HashSet<UserModel>();
		XStream stream = new XStream();
		// Fill userlist with existing users
		File dir = new File("Users");
		for (File subDir : dir.listFiles()) {
			if (subDir.isDirectory() && !subDir.isHidden()) {
				// Get the .hash and the keybox.xml
				File profileFile = new File(subDir.getPath() + "/profile");
				File keyBoxFile = new File(subDir.getPath() + "/keybox");
				if (profileFile.exists()) {
					// Profile is given - user already exists
					UserModel user = (UserModel) stream.fromXML(profileFile);
					this.mList.add(user);
					if (keyBoxFile.exists()) {
						// Keybox is saved as once, so recreate it too (if
						// existing)
						KeyBoxModel keyBox = (KeyBoxModel) stream
								.fromXML(keyBoxFile);
						user.setKeyBox(keyBox);
					} else {
						user.setKeyBox(new KeyBoxModel(user.getUserName()));
					}
				}
			}
		}
	}

	/*
	 * Methods
	 */
	public boolean add(UserModel user) {
		user.save();
		return this.mList.add(user);
	}

	public boolean remove(UserModel user) {
		if (user != null) {
			try {
				delete(new File("Users/" + user.getUserName()));
			} catch (IOException e) {
				throw new RuntimeException(
						"Directory of existing user could not be deleted!", e);
			}
			return this.mList.remove(user);
		}
		return false;
	}

	/**
	 * Returns the user with the given userName or null if such an user doesn't
	 * exist!
	 * 
	 * @param userName
	 *            of the user to look for
	 * @return the user or null if not found
	 */
	public UserModel get(String userName) {
		for (UserModel user : this.mList) {
			if (user.getUserName().equalsIgnoreCase(userName)) {
				return user;
			}
		}
		return null;
	}

	/**
	 * Check if the password of the user with the given user name is correct
	 * 
	 * @param username
	 * @param password
	 * @return true is password is correct
	 */
	public boolean checkPassword(String username, String password) {

		boolean isPasswordValid = false;

		UserModel user = this.get(username);
		if (user != null) {
			isPasswordValid = user.checkPassword(password);
		}

		setChanged();
		notifyObservers(isPasswordValid);
		return isPasswordValid;

	}

	/**
	 * Delete a file or an directory recursively !
	 * 
	 * @param file
	 *            or directory to delete recursively
	 * @throws IOException
	 */
	private static void delete(File file) throws IOException {
		if (file.isDirectory()) {
			// directory is empty, then delete it
			if (file.list().length == 0) {
				file.delete();
			} else {
				// list all the directory contents
				String files[] = file.list();

				for (String temp : files) {
					// construct the file structure
					File fileDelete = new File(file, temp);

					// recursive delete
					delete(fileDelete);
				}

				// check the directory again, if empty then delete it
				if (file.list().length == 0) {
					file.delete();
				}
			}

		} else {
			// if file, then delete it
			file.delete();
		}
	}

	@Override
	public Iterator<UserModel> iterator() {
		return this.mList.iterator();
	}
}
